package hivMultiCompartment;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

public class BCell extends Cell {
	
	public enum AgentState {
		NAIVE, ACTIVE, SLPC, LLPC, MEMORY
	}
	
	public AgentState state;
	public int antibodyProduciton;
	public boolean SHMSignal;
	public boolean terminalDifferentiation;
	
	public BCell() {
		super ();
		
		avgLife = GlobalConstants.avgLifeBNaive;
		life = GlobalConstants.sampleNormal(avgLife);
		
		moveInterval = GlobalConstants.moveIntervalB;
		
		probEnterLymph = GlobalConstants.probEnterLymphBNaive;
		probEnterThymus = probEnterLymph + GlobalConstants.probEnterThymusBNaive;
		probExit = GlobalConstants.probExitBNaive;

		setColor(GlobalConstants.colorBNaive);
		proliferateCount = 0;
		
		antibodyProduciton = 0;
		SHMSignal = false;
		terminalDifferentiation = false;
		state = AgentState.NAIVE;
		
		recognizeStrain = Model.getUniformIntFromTo(1, GlobalConstants.maxIdiotypeB);
	}
	
	public void statesAndInteractions(){
		if(!alive) return;
		switch(state){
			case ACTIVE:
				//search for matching CD4 Effector
				if(Organ2D != null) {
					if (getMatchingCD4TEffector()) {
						double r = Model.getUniformDoubleFromTo(0, 1);
						if(r < GlobalConstants.probCD4EffectorActivateBActive){
							//System.out.println("SLPC!"+this.toString());
							changeState(AgentState.SLPC);
						}
					}
				}
				break;
			case SLPC:
				if(Organ2D != null){
					Organ2D.addAntibodyAt(x, y, antibodyProduciton);
				}
				//after the last division, decide differentiation
				if(proliferateCount == 0) {
					if(SHMSignal){
						double r = Model.getUniformDoubleFromTo(0, 1);
						if(r < GlobalConstants.memoryFrqB) {
							changeState(AgentState.MEMORY);
						}else {
							changeState(AgentState.LLPC);
							terminalDifferentiation = true;
						}
					}else {
						terminalDifferentiation = true;
					}
				}
				break;
			case LLPC:
				if(Organ2D != null){
					Organ2D.addAntibodyAt(x, y, antibodyProduciton);
				}
				break;
			default://NAIVE or MEMORY
				if(Organ2D != null){
					if(getMatchingVirus()){
						//System.out.println("activation!");
						activate();
					}
				}
				break;
		}
	}
	
	private boolean getMatchingCD4TEffector(){
		boolean result = false;
		ArrayList<Object> cList = Organ2D.cellSpace.getMooreNeighborOfType(x, y, 5, CD4TCell.class);
		Iterator<Object> cIter = cList.iterator();
		while(cIter.hasNext()) {
			CD4TCell c = (CD4TCell)cIter.next();
			if(c.isAlive() && c.isEffector() && c.recognizeStrain == presentStrain) {
				result = true;
				break;
			}
		}
		return result;
	}
	/**
	 * search for matching virus in current location
	 * if found, kills virus and return true
	 * @return
	 */
	private boolean getMatchingVirus(){
		boolean result = false;
		Virus v = null;
		HashSet<Virus> vList = (HashSet<Virus>)Organ2D.virusSpace.getObjectAt(x, y);
		Iterator<Virus> vIter = vList.iterator();
		while (vIter.hasNext()) {
			Virus vt = vIter.next();
			if (vt.myStrain == recognizeStrain && vt.isAlive()){
				presentStrain = recognizeStrain;
				v = vt;
				break;
			}
		}
		if(v != null) {
			v.agentDie();
			result = true;
			
		}
		return result;
	}
	/**
	 * naive or memory encounters antigen and activates
	 */
	public void activate(){
		if(state == AgentState.NAIVE) {
			changeState(AgentState.ACTIVE);
		}else{//memory
			changeState(AgentState.SLPC);
		}
	}
	
	public boolean isSLPC(){
		return (state == AgentState.SLPC);
	}
	
	/**
	 * change state and parameters
	 * @param s
	 */
	public void changeState(AgentState s) {
		state = s;
		switch (s) {
			case ACTIVE:
				avgLife = GlobalConstants.avgLifeBActive;
				life = GlobalConstants.sampleNormal(avgLife);
				probExit = GlobalConstants.probExitBActive;
				probEnterLymph = GlobalConstants.probEnterLymphBActive;
				probEnterThymus = GlobalConstants.probEnterThymusBActive;
				limitedPorliferation = true;
				break;
			case SLPC:
				avgLife = GlobalConstants.avgLifeBSLPC;
				life = GlobalConstants.sampleNormal(avgLife);
				probExit = GlobalConstants.probExitBSLPC;
				probEnterLymph = GlobalConstants.probEnterLymphBSLPC;
				probEnterThymus = GlobalConstants.probEnterThymusBSLPC;
				proliferateCount = GlobalConstants.dividingCountBSLPC;
				proliferateInterval = GlobalConstants.doublingTimeBPC;
				proliferateCD = proliferateInterval;
				antibodyProduciton = GlobalConstants.antibodyProductionBSLPC;
				setColor(GlobalConstants.colorBSLPC);
				limitedPorliferation = true;
				break;
			case LLPC:
				avgLife = GlobalConstants.avgLifeBLLPC;
				life = GlobalConstants.sampleNormal(avgLife);
				probExit = GlobalConstants.probExitBLLPC;
				probEnterLymph = GlobalConstants.probEnterLymphBLLPC;
				probEnterThymus = GlobalConstants.probEnterThymusBLLPC;
				proliferateCount = GlobalConstants.dividingCountBLLPC;
				proliferateInterval = GlobalConstants.doublingTimeBPC;
				proliferateCD = proliferateInterval;
				antibodyProduciton = GlobalConstants.antibodyProductionBSLPC;
				limitedPorliferation = true;
				break;
			case MEMORY:
				avgLife = GlobalConstants.avgLifeBMemory;
				life = GlobalConstants.sampleNormal(avgLife);
				probExit = GlobalConstants.probExitBMemory;
				probEnterLymph = GlobalConstants.probEnterLymphBMemory;
				probEnterThymus = GlobalConstants.probEnterThymusBMemory;
				proliferateCount = 1;
				limitedPorliferation = true;
				antibodyProduciton = 0;
				break;
			default:
				//naive. won't happen.
				break;
		}
	}
	
}
